from elementtree.ElementTree import Element
from elementtree import ElementTree
import l3dgecomms

#Define in game metrics
METRIC_ONE=1
METRIC_TWO=2
METRIC_THREE=3
METRIC_FOUR=4
METRIC_FIVE=5
METRIC_SIX=6
METRIC_SEVEN=7
METRIC_EIGHT=8
METRIC_NINE=9
METRIC_TEN=10
METRIC_ZERO=0

METRIC_SPIN=METRIC_ONE
METRIC_BOUNCE_HEIGHT=METRIC_TWO
METRIC_SCALE=METRIC_THREE
METRIC_ROLL=METRIC_FOUR
METRIC_COLOR=METRIC_FIVE
METRIC_BOUNCE_RATE=METRIC_SIX 
METRIC_SOUND=METRIC_SEVEN
METRIC_ALT_SKIN=METRIC_EIGHT
METRIC_ALT_MODEL=METRIC_NINE 
METRIC_UNUSED=METRIC_TEN
METRIC_INFO=METRIC_ZERO

#Define ASTERISK metrics
AVG_CALL_DURATION="AvgCallDuration"
NO_MOBILE_CALLS="NoMobileCalls"
CURRENT_CHANNELS="CurrentChannels"
CURRENT_CALLS="CurrentCalls"
ASTERISK_UPTIME="AsteriskUptime"
NO_INTERNAT_CALLS="NoInternationalCalls"
NO_INTERNAL_CALLS="NoInternalCalls"
NO_INTERSTA_CALLS="NoInterstateCalls"
NO_LOCAL_CALLS="NoLocalCalls"
RELOAD_TIME="AsteriskReloadtime"

MAX_CALLS=100
MAX_DURATION=600 

#Define SERVER metrics
CPU_IDLE="cpu_idle"
BYTES_IN="bytes_in"
BYTES_OUT="bytes_out"
MEM_FREE="mem_free"
MEM_TOT="mem_total"
MAX_BYTES_IN=1048000

#Define client metrics
ON_HOOK="OnHook"
DIALED="Dialed"
SIP_IP="SipPhoneIP"


#define l3dgecomms message types
FIELD_NAME="n"
FIELD_VALUE="v"
FIELD_RATE="r"

class Entity:
	def __init__(self, name, parentName, type, id, adminWeight):
		self.name = name
		self.parentName=parentName
		self.type = type
		self.id = id
		self.adminWeight = adminWeight


class Metric:
	def __init__(self, name, visual, value=None, description="", rate=""):
		self.name = name
		self.visual = int(visual)
		self.value = value
		self.description = str(description)
		self.rate = str(rate)
	
	
	def updateEntity(self, HostID):
		print str(HostID) + "," + str(self.visual) + "," + str(self.name) + "," + str(self.rate) + "," + str(self.description)
		l3dgecomms.sendMessage(int(HostID),int(self.visual),FIELD_NAME,str(self.name))
		l3dgecomms.sendMessage(int(HostID),int(self.visual),FIELD_RATE,str(self.rate))
		l3dgecomms.sendMessage(int(HostID),int(self.visual),FIELD_VALUE,str(self.description))


class Cluster:
	entity=None
	hosts={}
	metrics={}
	
	metrics["Summary"] = Metric("Summary", METRIC_INFO)
	metrics["Bytes In"] = Metric("Bytes In", METRIC_BOUNCE_HEIGHT)
	metrics[CURRENT_CALLS] = Metric(CURRENT_CALLS, METRIC_SPIN)
	
	#Parses the XML for metrics of this object and its children
	def doMetrics(self, clusterElmt):
		print "Filling out metrics for cluster " + clusterElmt.attrib["NAME"]
		for hostElmt in clusterElmt.getiterator("HOST"):
			try:
				#get the host object for xml node
				host = self.hosts[hostElmt.attrib["NAME"]]
				host.doMetrics(hostElmt)
				break
			except KeyError:
				print "Could not find host " + hostElmt.attrib["NAME"]
		self.summarise()
	
	
	#Summarises statistics of all hosts in the cluster
	def summarise(self):
		bytesIn=0
		calls=0
		for host in self.hosts.values():
			bytesIn += host.serverMetrics["Bytes In"].value
			calls += int(host.asteriskMetrics[CURRENT_CALLS].value)
		
		byterate = min((bytesIn/MAX_BYTES_IN)*50,50)
		unit="bytes/sec"
		if bytesIn > 1024:
			bytesIn = bytesIn/1024
			unit="Kbytes/sec"
			if bytesIn > 1024:
				bytesIn = bytesIn/1024
				unit="Mbytes/sec"
		
		callrate = min((float(calls)/MAX_CALLS)*200, 200)
		
		self.metrics["Bytes In"].description=str(bytesIn) + " " + unit
		self.metrics["Bytes In"].rate=str(byterate)
		self.metrics[CURRENT_CALLS].description=str(calls) + " Calls"
		self.metrics[CURRENT_CALLS].rate=str(callrate)
		
		summary = "Number of servers: " + str(len(self.hosts)) + "@"
		summary += "Current calls: " + str(calls) + "@"
		summary += "Bytes In: " + str(bytesIn) + " " + unit + "@"
		
		self.metrics["Summary"].description = summary
	
	#Causes update messages to be sent to the LAMS server
	def updateLAMS(self):
		print "Sending messages to lams"
		for metric in self.metrics.values():
			metric.updateEntity(self.entity.id)
		for host in self.hosts.values():
			host.updateLAMS()
	
	def clearMetrics(self):
		for metric in self.metrics.values():
			metric.description = "0"
			metric.rate = "0"
			
		for host in self.hosts.values():
			host.clearMetrics()


class Host:
	clientPool=[]
	clients={}
	serverEntity=None
	asteriskEntity=None
	
	serverMetrics={}
	serverMetrics["Summary"] = Metric("Summary", METRIC_INFO)
	serverMetrics["CPU Usage"] = Metric("CPU Usage", METRIC_SPIN)
	serverMetrics["Bytes In"] = Metric("Bytes In", METRIC_BOUNCE_HEIGHT)
	serverMetrics["Memory Usage"] = Metric("Memory Usage", METRIC_SCALE)
	
	asteriskMetrics={}
	asteriskMetrics["Summary"] = Metric("Summary", METRIC_INFO)
	asteriskMetrics[CURRENT_CALLS] = Metric(CURRENT_CALLS, METRIC_SPIN)
	asteriskMetrics[AVG_CALL_DURATION] = Metric(AVG_CALL_DURATION, METRIC_BOUNCE_RATE)
	
	#summaries for info window metric
	asteriskSummary=""
	serverSummary=""
	
	#Find metrics to visualise
	memfree=None
	memTot=None
	
	#Causes update messages to be sent to the LAMS server
	def updateLAMS(self):
		for metric in self.serverMetrics.values():
			metric.updateEntity(self.serverEntity.id)
		for metric in self.asteriskMetrics.values():
			metric.updateEntity(self.asteriskEntity.id)
		for client in self.clients.values():
			client.updateLAMS()
	
	
	def clearMetrics(self):
		for metric in self.asteriskMetrics.values():
			metric.description = "0"
			metric.rate = "0"
		for metric in self.serverMetrics.values():
			metric.description = "0"
			metric.rate = "0"
			
		while len(self.clients.values()):
			client = self.clients.values().pop()
			client.clearMetrics()
			clientPool.append(client)
	
	
	#Parses the XML for metrics of this object and its children
	def doMetrics(self, hostElmt):
		print "Filling out metrics for host " + hostElmt.attrib["NAME"]
		
		for metricElmt in hostElmt.getiterator("METRIC"):
			metricName = metricElmt.attrib["NAME"]
			if metricName.startswith(self.asteriskEntity.name + "-Client:"):
				clientName=metricName[metricName.rfind(":")+1:metricName.rfind("-")]
				
				#try to find this client
				if clientName in self.clients:
					client=self.clients[clientName]
				else:
					client = self.clientPool.pop()
					client.metrics["Summary"].description = "Client name: " + clientName + "@"
					self.clients[clientName] = client
				
				client.doMetric(metricElmt)
				
			elif metricName.startswith(self.asteriskEntity.name):
				self.doAsteriskMetric(metricElmt)
			else:
				self.doServerMetric(metricElmt)	
		
		#add summary metrics
		self.asteriskMetrics["Summary"].description = self.asteriskSummary
		self.serverMetrics["Summary"].description = self.serverSummary
	
	def doAsteriskMetric(self, metricElmt):
		#print "doAsteriskMetric"
		metricName = metricElmt.attrib["NAME"]
		metricName = metricName[metricName.find("-")+1:]
		metricVal = metricElmt.attrib["VAL"]
		metricUnit = metricElmt.attrib["UNITS"]
		#Add all info to the summary
		self.asteriskSummary += metricName + ": " + metricVal + " " + metricUnit + "@"
		
		#Find metrics to visualise
		if metricName == CURRENT_CALLS:
			spinrate = min((float(metricVal)/MAX_CALLS)*200, 200)
			self.asteriskMetrics[CURRENT_CALLS].value = metricVal
			self.asteriskMetrics[CURRENT_CALLS].description = metricVal + " " + metricUnit
			self.asteriskMetrics[CURRENT_CALLS].rate = str(spinrate)
		elif metricName == AVG_CALL_DURATION:
			bounceRate = min((float(metricVal)/MAX_DURATION)*100, 100)
			self.asteriskMetrics[AVG_CALL_DURATION].value = metricVal
			self.asteriskMetrics[AVG_CALL_DURATION].description = metricVal + " " + metricUnit
			self.asteriskMetrics[AVG_CALL_DURATION].rate = str(bounceRate)
	
	def doServerMetric(self, metricElmt):
		#print "doServerMetric"
		metricName = metricElmt.get("NAME")
		metricVal = metricElmt.get("VAL")
		metricUnit = metricElmt.get("UNITS")
		
		#Add all info to the summary
		self.serverSummary += metricName + ": " + metricVal + " " + metricUnit + "@"
		
		if metricName == CPU_IDLE:
			cpuUsage = 100 - float(metricVal)
			self.serverMetrics["CPU Usage"].value = cpuUsage
			self.serverMetrics["CPU Usage"].description = str(cpuUsage) + " " + metricUnit
			self.serverMetrics["CPU Usage"].rate = str(cpuUsage)
		elif metricName == BYTES_IN:
			bytesIn=float(metricVal)
			unit="bytes/sec"
			if bytesIn > 1024:
				bytesIn = bytesIn/1024
				unit="Kbytes/sec"
				if bytesIn > 1024:
					bytesIn = bytesIn/1024
					unit="Mbytes/sec"
			rate = min((float(metricVal)/MAX_BYTES_IN)*50,50)
			self.serverMetrics["Bytes In"].value = float(metricVal)
			self.serverMetrics["Bytes In"].description = str(bytesIn) + " " + unit
			self.serverMetrics["Bytes In"].rate = str(rate)
		elif metricName == MEM_FREE:
			self.memfree = float(metricVal)
		elif metricName == MEM_TOT:
			self.memTot = float(metricVal)
		
		if self.memfree and self.memTot:
			memUsed=(1-(self.memfree / self.memTot))*100
			self.serverMetrics["Memory Usage"].value = memUsed
			self.serverMetrics["Memory Usage"].description = str(memUsed) + " %"
			self.serverMetrics["Memory Usage"].rate = str(memUsed/2)


class Client:
	entity=None
	metrics={}
	metrics["Summary"] = Metric("Summary", METRIC_INFO)
	metrics["In Call"] = Metric("In Call", METRIC_SPIN)
	metrics["IP Address"] = Metric("IP Address", METRIC_BOUNCE_HEIGHT)
	metrics["Dialled No"] = Metric("Dialled No", METRIC_COLOR)
	
	#Parses the XML for metrics of this object
	def doMetric(self, metricElmt):
		metricName = metricElmt.get("NAME")
		metricVal = metricElmt.get("VAL")
		metricUnit = metricElmt.get("UNITS")
		
		if metricName.endswith(SIP_IP) and metricVal != "Unknown":
			self.metrics["Summary"].description += "IP Address: " + metricVal + "@"
			self.metrics["IP Address"].value = metricVal
			self.metrics["IP Address"].description = metricVal
			self.metrics["IP Address"].rate = 10
		elif metricName.endswith(ON_HOOK):
			self.metrics["Summary"].description += "In Call: " + metricVal + "@"
			self.metrics["In Call"].value = metricVal
			self.metrics["In Call"].description = metricVal
			if metricVal == "yes":
				self.metrics["In Call"].rate = 100
			else:
				self.metrics["In Call"].rate = 0
		elif metricName.endswith(DIALED) and metricVal != "no":
			self.metrics["Summary"].description += "Dialled No: " + metricVal + "@"
			self.metrics["Dialled No"].value = metricVal
			self.metrics["Dialled No"].description = metricVal
			self.metrics["Dialled No"].rate = "FFFFFF"
		
	#Causes update messages to be sent to the LAMS server
	def updateLAMS(self):
		for metric in self.metrics.values():
			metric.updateEntity(self.entity.id)
	
	def clearMetrics(self):
		for metric in self.metrics.values():
			metric.description = "0"
			metric.rate = "0"

